Always build libraries into the same location
authorAlex Crichton <alex@alexcrichton.com>
Mon, 25 Jul 2016 20:27:06 +0000 (13:27 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Wed, 27 Jul 2016 00:52:45 +0000 (17:52 -0700)
Previously Cargo would compile a library into a different location depending on
whether it was the "root crate" or not. In the ongoing saga of reducing Cargo's
reliance on the idea of a "root crate" this PR is the next step. With workspaces
the root crate of a compliation changes all the time, so the output needs to be
the same whether a crate is at the root or not.

Fixing this inconsistence in turn fixes bugs like #2855 and #2897 which arise
due to this discrepancy. Additionally, Cargo will no longer recompile a library
when it's used as a "root crate" or not.

This is fixed by taking a few steps:

* Everything is now compiled into the `deps` directory, regardless of whether
  it's a root output or not.
* If a "root crate" is being compiled, then the relevant outputs are hard-linked
  up one level to where they are today. This means that your binaries, dylibs,
  staticlibs, etc, will all show up where they used to.
* The `-C metadata` flag is always omitted for path dependencies now. These
  dependencies are always path dependencies and already all have unique crate
  names. Additionally, they're the only crates in the DAG without metadata, so
  there's no need to provide additional metadata. This in turn means that none
  of the file names of the generated crates are mangled.

Closes #2855

18 files changed:
src/cargo/ops/cargo_clean.rs
src/cargo/ops/cargo_rustc/context.rs
src/cargo/ops/cargo_rustc/custom_build.rs
src/cargo/ops/cargo_rustc/fingerprint.rs
src/cargo/ops/cargo_rustc/layout.rs
src/cargo/ops/cargo_rustc/mod.rs
src/cargo/ops/cargo_test.rs
tests/build-lib.rs
tests/build-script.rs
tests/build.rs
tests/cargo_alias_config.rs
tests/cross-compile.rs
tests/plugins.rs
tests/profiles.rs
tests/run.rs
tests/rustc.rs
tests/rustdoc.rs
tests/workspaces.rs

index 88c8c933ad9adc4fc7786f62cf0781f4db77d4cf..21cb053d12cd25b0e357b37d6a4a3e979ada515c 100644 (file)
@@ -73,7 +73,7 @@ pub fn clean(ws: &Workspace, opts: &CleanOptions) -> CargoResult<()> {
     try!(cx.probe_target_info(&units));
 
     for unit in units.iter() {
-        let layout = cx.layout(&unit.pkg, unit.kind);
+        let layout = cx.layout(unit);
         try!(rm_rf(&layout.proxy().fingerprint(&unit.pkg)));
         try!(rm_rf(&layout.build(&unit.pkg)));
 
index 4df862ffd5d61d6e9cb8a18e90af50ef55de795b..fb9acab305592a4b3656fa21e959c8f4f7243903 100644 (file)
@@ -96,7 +96,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
 
     /// Prepare this context, ensuring that all filesystem directories are in
     /// place.
-    pub fn prepare(&mut self, root: &Package) -> CargoResult<()> {
+    pub fn prepare(&mut self) -> CargoResult<()> {
         let _p = profile::start("preparing layout");
 
         try!(self.host.prepare().chain_error(|| {
@@ -111,10 +111,9 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
             None => {}
         }
 
-        self.compilation.root_output =
-                self.layout(root, Kind::Target).proxy().dest().to_path_buf();
-        self.compilation.deps_output =
-                self.layout(root, Kind::Target).proxy().deps().to_path_buf();
+        let layout = self.target.as_ref().unwrap_or(&self.host);
+        self.compilation.root_output = layout.dest().to_path_buf();
+        self.compilation.deps_output = layout.deps().to_path_buf();
         Ok(())
     }
 
@@ -237,9 +236,9 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
     }
 
     /// Returns the appropriate directory layout for either a plugin or not.
-    pub fn layout(&self, pkg: &Package, kind: Kind) -> LayoutProxy {
-        let primary = pkg.package_id() == self.resolve.root();
-        match kind {
+    pub fn layout(&self, unit: &Unit) -> LayoutProxy {
+        let primary = unit.pkg.package_id() == self.resolve.root();
+        match unit.kind {
             Kind::Host => LayoutProxy::new(&self.host, primary),
             Kind::Target => LayoutProxy::new(self.target.as_ref()
                                                  .unwrap_or(&self.host),
@@ -247,13 +246,18 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
         }
     }
 
+    /// Returns the path for plugin/dylib dependencies
+    pub fn host_dylib_path(&self) -> &Path {
+        self.host.deps()
+    }
+
     /// Returns the appropriate output directory for the specified package and
     /// target.
     pub fn out_dir(&self, unit: &Unit) -> PathBuf {
         if unit.profile.doc {
-            self.layout(unit.pkg, unit.kind).doc_root()
+            self.layout(unit).doc_root()
         } else {
-            self.layout(unit.pkg, unit.kind).out_dir(unit.pkg, unit.target)
+            self.layout(unit).out_dir(unit)
         }
     }
 
@@ -289,7 +293,7 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
             let mut metadata = unit.pkg.generate_metadata();
             metadata.mix(&format!("bin-{}", unit.target.name()));
             Some(metadata)
-        } else if unit.pkg.package_id() == self.resolve.root() &&
+        } else if unit.pkg.package_id().source_id().is_path() &&
                   !unit.profile.test {
             // If we're not building a unit test then the root package never
             // needs any metadata as it's guaranteed to not conflict with any
index 071c7079d73d75360acde37c060ecb54041b3ddf..e2ea45226285795479a882a338a487f7807c54ed 100644 (file)
@@ -87,9 +87,10 @@ pub fn prepare<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
 
 fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
                         -> CargoResult<(Work, Work)> {
+    let host_unit = Unit { kind: Kind::Host, ..*unit };
     let (script_output, build_output) = {
-        (cx.layout(unit.pkg, Kind::Host).build(unit.pkg),
-         cx.layout(unit.pkg, unit.kind).build_out(unit.pkg))
+        (cx.layout(&host_unit).build(unit.pkg),
+         cx.layout(unit).build_out(unit.pkg))
     };
 
     // Building the command to execute
@@ -161,8 +162,8 @@ fn build_work<'a, 'cfg>(cx: &mut Context<'a, 'cfg>, unit: &Unit<'a>)
     };
     cx.build_explicit_deps.insert(*unit, (output_file.clone(), rerun_if_changed));
 
-    try!(fs::create_dir_all(&cx.layout(unit.pkg, Kind::Host).build(unit.pkg)));
-    try!(fs::create_dir_all(&cx.layout(unit.pkg, unit.kind).build(unit.pkg)));
+    try!(fs::create_dir_all(&cx.layout(&host_unit).build(unit.pkg)));
+    try!(fs::create_dir_all(&cx.layout(unit).build(unit.pkg)));
 
     // Prepare the unit of "dirty work" which will actually run the custom build
     // command.
index 60ff14c2b83937f81dcad34312bd24a7ee1cdf75..e8ad1880f8a430283f9229c1f1c66037717b608f 100644 (file)
@@ -497,7 +497,7 @@ pub fn prepare_init(cx: &mut Context, unit: &Unit) -> CargoResult<()> {
 
 /// Return the (old, new) location for fingerprints for a package
 pub fn dir(cx: &Context, unit: &Unit) -> PathBuf {
-    cx.layout(unit.pkg, unit.kind).proxy().fingerprint(unit.pkg)
+    cx.layout(unit).proxy().fingerprint(unit.pkg)
 }
 
 /// Returns the (old, new) location for the dep info file of a target.
index 67c2341fa799ce6bbf650ed5661ab28a6aae6bd0..f96ce5715d82be130d9b60038b51647c0c2b6769 100644 (file)
@@ -49,9 +49,10 @@ use std::fs;
 use std::io;
 use std::path::{PathBuf, Path};
 
-use core::{Package, Target, Workspace};
+use core::{Package, Workspace};
 use util::{Config, FileLock, CargoResult, Filesystem};
 use util::hex::short_hash;
+use super::Unit;
 
 pub struct Layout {
     root: PathBuf,
@@ -165,11 +166,13 @@ impl<'a> LayoutProxy<'a> {
 
     pub fn proxy(&self) -> &'a Layout { self.root }
 
-    pub fn out_dir(&self, pkg: &Package, target: &Target) -> PathBuf {
-        if target.is_custom_build() {
-            self.build(pkg)
-        } else if target.is_example() {
+    pub fn out_dir(&self, unit: &Unit) -> PathBuf {
+        if unit.target.is_custom_build() {
+            self.build(unit.pkg)
+        } else if unit.target.is_example() {
             self.examples().to_path_buf()
+        } else if unit.target.is_lib() {
+            self.deps().to_path_buf()
         } else {
             self.root().to_path_buf()
         }
index 2342352c51d6cae4605225649047c63c14114ceb..bffb0b63f89051c8021a78352967a486043e8515 100644 (file)
@@ -87,7 +87,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>,
 
     let mut queue = JobQueue::new(&cx);
 
-    try!(cx.prepare(root));
+    try!(cx.prepare());
     try!(cx.probe_target_info(&units));
     try!(custom_build::build_map(&mut cx, &units));
 
@@ -104,7 +104,7 @@ pub fn compile_targets<'a, 'cfg: 'a>(ws: &Workspace<'cfg>,
     try!(queue.execute(&mut cx));
 
     for unit in units.iter() {
-        let out_dir = cx.layout(unit.pkg, unit.kind).build_out(unit.pkg)
+        let out_dir = cx.layout(unit).build_out(unit.pkg)
                         .display().to_string();
         cx.compilation.extra_env.entry(unit.pkg.package_id().clone())
           .or_insert(Vec::new())
@@ -228,6 +228,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult<Work> {
     let do_rename = unit.target.allows_underscores() && !unit.profile.test;
     let real_name = unit.target.name().to_string();
     let crate_name = unit.target.crate_name();
+    let move_outputs_up = unit.pkg.package_id() == cx.resolve.root();
 
     let rustc_dep_info_loc = if do_rename {
         root.join(&crate_name)
@@ -271,7 +272,7 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult<Work> {
             let src = dst.with_file_name(dst.file_name().unwrap()
                                             .to_str().unwrap()
                                             .replace(&real_name, &crate_name));
-            if !has_custom_args || fs::metadata(&src).is_ok() {
+            if !has_custom_args || src.exists() {
                 try!(fs::rename(&src, &dst).chain_error(|| {
                     internal(format!("could not rename crate {:?}", src))
                 }));
@@ -286,6 +287,40 @@ fn rustc(cx: &mut Context, unit: &Unit) -> CargoResult<Work> {
             try!(fingerprint::append_current_dir(&dep_info_loc, &cwd));
         }
 
+        // If we're a "root crate", e.g. the target of this compilation, then we
+        // hard link our outputs out of the `deps` directory into the directory
+        // above. This means that `cargo build` will produce binaries in
+        // `target/debug` which one probably expects.
+        if move_outputs_up {
+            for &(ref filename, _linkable) in filenames.iter() {
+                let src = root.join(filename);
+                // This may have been a `cargo rustc` command which changes the
+                // output, so the source may not actually exist.
+                if !src.exists() {
+                    continue
+                }
+
+                // We currently only lift files up from the `deps` directory. If
+                // it was compiled into something like `example/` or `doc/` then
+                // we don't want to link it up.
+                let src_dir = src.parent().unwrap();
+                if !src_dir.ends_with("deps") {
+                    continue
+                }
+                let dst = src_dir.parent().unwrap()
+                                 .join(src.file_name().unwrap());
+                if dst.exists() {
+                    try!(fs::remove_file(&dst).chain_error(|| {
+                        human(format!("failed to remove: {}", dst.display()))
+                    }));
+                }
+                try!(fs::hard_link(&src, &dst).chain_error(|| {
+                    human(format!("failed to link `{}` to `{}`",
+                                  src.display(), dst.display()))
+                }));
+            }
+        }
+
         Ok(())
     }));
 
@@ -390,8 +425,7 @@ fn rustdoc(cx: &mut Context, unit: &Unit) -> CargoResult<Work> {
     try!(build_deps_args(&mut rustdoc, cx, unit));
 
     if unit.pkg.has_custom_build() {
-        rustdoc.env("OUT_DIR", &cx.layout(unit.pkg, unit.kind)
-                                  .build_out(unit.pkg));
+        rustdoc.env("OUT_DIR", &cx.layout(unit).build_out(unit.pkg));
     }
 
     rustdoc.args(&try!(cx.rustdocflags_args(unit)));
@@ -552,12 +586,7 @@ fn build_plugin_args(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit) {
 
 fn build_deps_args(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit)
                    -> CargoResult<()> {
-    let layout = cx.layout(unit.pkg, unit.kind);
-    cmd.arg("-L").arg(&{
-        let mut root = OsString::from("dependency=");
-        root.push(layout.root());
-        root
-    });
+    let layout = cx.layout(unit);
     cmd.arg("-L").arg(&{
         let mut deps = OsString::from("dependency=");
         deps.push(layout.deps());
@@ -569,7 +598,7 @@ fn build_deps_args(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit)
     }
 
     for unit in try!(cx.dep_targets(unit)).iter() {
-        if unit.target.linkable() {
+        if unit.target.linkable() && !unit.profile.doc {
             try!(link_to(cmd, cx, unit));
         }
     }
@@ -578,8 +607,6 @@ fn build_deps_args(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit)
 
     fn link_to(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit)
                -> CargoResult<()> {
-        let layout = cx.layout(unit.pkg, unit.kind);
-
         for (filename, linkable) in try!(cx.target_filenames(unit)) {
             if !linkable {
                 continue
@@ -587,7 +614,7 @@ fn build_deps_args(cmd: &mut CommandPrototype, cx: &Context, unit: &Unit)
             let mut v = OsString::new();
             v.push(&unit.target.crate_name());
             v.push("=");
-            v.push(layout.root());
+            v.push(cx.out_dir(unit));
             v.push(&path::MAIN_SEPARATOR.to_string());
             v.push(&filename);
             cmd.arg("--extern").arg(&v);
@@ -600,9 +627,8 @@ pub fn process(cmd: CommandType, pkg: &Package,
                cx: &Context) -> CargoResult<CommandPrototype> {
     // When invoking a tool, we need the *host* deps directory in the dynamic
     // library search path for plugins and such which have dynamic dependencies.
-    let layout = cx.layout(pkg, Kind::Host);
     let mut search_path = util::dylib_path();
-    search_path.push(layout.deps().to_path_buf());
+    search_path.push(cx.host_dylib_path().to_path_buf());
 
     // We want to use the same environment and such as normal processes, but we
     // want to override the dylib search path with the one we just calculated.
index 52365c6e60d1a21565169ee7c3ccd3c03c830e46..44a51be30174c99147a605a350f3a19dd5a2a2b5 100644 (file)
@@ -134,7 +134,7 @@ fn run_doc_tests(options: &TestOptions,
             p.arg("--test").arg(lib)
              .arg("--crate-name").arg(&crate_name);
 
-            for &rust_dep in &[&compilation.deps_output, &compilation.root_output] {
+            for &rust_dep in &[&compilation.deps_output] {
                 let mut arg = OsString::from("dependency=");
                 arg.push(rust_dep);
                 p.arg("-L").arg(arg);
index f2b42aea7776d9c68ab7353ce06f55ebde12157c..3d8a44108dc4f71231fa49d1d66b93bd30b7c114 100644 (file)
@@ -10,9 +10,8 @@ fn verbose_output_for_lib(p: &ProjectBuilder) -> String {
     format!("\
 [COMPILING] {name} v{version} ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name {name} --crate-type lib -g \
-        --out-dir {dir}{sep}target{sep}debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
index b599f452c5d2c27535ce86efc6bdb69ea9430a81..3cc250af3f1b80f92a818c8f971a09f78473cc00 100644 (file)
@@ -766,19 +766,17 @@ fn build_cmd_with_a_build_cmd() {
 [RUNNING] `rustc a[..]build.rs [..] --extern b=[..]`
 [RUNNING] `[..]a-[..]build-script-build[..]`
 [RUNNING] `rustc [..]lib.rs --crate-name a --crate-type lib -g \
-    -C metadata=[..] -C extra-filename=-[..] \
     --out-dir [..]target[..]deps --emit=dep-info,link \
-    -L [..]target[..]deps -L [..]target[..]deps`
+    -L [..]target[..]deps`
 [COMPILING] foo v0.5.0 (file://[..])
 [RUNNING] `rustc build.rs --crate-name build_script_build --crate-type bin \
-    -g \
-    --out-dir [..]build[..]foo-[..] --emit=dep-info,link \
-    -L [..]target[..]debug -L [..]target[..]deps \
-    --extern a=[..]liba-[..].rlib`
+    -g --out-dir [..] --emit=dep-info,link \
+    -L [..]target[..]deps \
+    --extern a=[..]liba[..].rlib`
 [RUNNING] `[..]foo-[..]build-script-build[..]`
 [RUNNING] `rustc [..]lib.rs --crate-name foo --crate-type lib -g \
-    --out-dir [..]target[..]debug --emit=dep-info,link \
-    -L [..]target[..]debug -L [..]target[..]deps`
+    --out-dir [..] --emit=dep-info,link \
+    -L [..]target[..]deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 "));
 }
@@ -1175,7 +1173,7 @@ fn build_script_with_dynamic_native_dependency() {
 
             fn main() {
                 let src = PathBuf::from(env::var("SRC").unwrap());
-                println!("cargo:rustc-link-search={}/target/debug",
+                println!("cargo:rustc-link-search={}/target/debug/deps",
                          src.display());
             }
         "#)
index c45d50660c6ea2ead2f01b56886eddcfc14077ff..aa3ec6e6643bfae93432f1f67c1927db59626a98 100644 (file)
@@ -1026,7 +1026,6 @@ fn lto_build() {
         -C lto \
         --out-dir {dir}[..]target[..]release \
         --emit=dep-info,link \
-        -L dependency={dir}[..]target[..]release \
         -L dependency={dir}[..]target[..]release[..]deps`
 [FINISHED] release [optimized] target(s) in [..]
 ",
@@ -1051,9 +1050,8 @@ fn verbose_build() {
                 execs().with_status(0).with_stderr(&format!("\
 [COMPILING] test v0.0.0 ({url})
 [RUNNING] `rustc src[..]lib.rs --crate-name test --crate-type lib -g \
-        --out-dir {dir}[..]target[..]debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}[..]target[..]debug \
         -L dependency={dir}[..]target[..]debug[..]deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ",
@@ -1079,9 +1077,8 @@ fn verbose_release_build() {
 [COMPILING] test v0.0.0 ({url})
 [RUNNING] `rustc src[..]lib.rs --crate-name test --crate-type lib \
         -C opt-level=3 \
-        --out-dir {dir}[..]target[..]release \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}[..]target[..]release \
         -L dependency={dir}[..]target[..]release[..]deps`
 [FINISHED] release [optimized] target(s) in [..]
 ",
@@ -1123,22 +1120,18 @@ fn verbose_release_build_deps() {
 [RUNNING] `rustc foo[..]src[..]lib.rs --crate-name foo \
         --crate-type dylib --crate-type rlib -C prefer-dynamic \
         -C opt-level=3 \
-        -C metadata=[..] \
-        -C extra-filename=-[..] \
-        --out-dir {dir}[..]target[..]release[..]deps \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}[..]target[..]release[..]deps \
         -L dependency={dir}[..]target[..]release[..]deps`
 [COMPILING] test v0.0.0 ({url})
 [RUNNING] `rustc src[..]lib.rs --crate-name test --crate-type lib \
         -C opt-level=3 \
-        --out-dir {dir}[..]target[..]release \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}[..]target[..]release \
         -L dependency={dir}[..]target[..]release[..]deps \
         --extern foo={dir}[..]target[..]release[..]deps[..]\
-                     {prefix}foo-[..]{suffix} \
-        --extern foo={dir}[..]target[..]release[..]deps[..]libfoo-[..].rlib`
+                     {prefix}foo{suffix} \
+        --extern foo={dir}[..]target[..]release[..]deps[..]libfoo.rlib`
 [FINISHED] release [optimized] target(s) in [..]
 ",
                     dir = p.root().display(),
@@ -1783,14 +1776,14 @@ fn compile_then_delete() {
         "#)
         .file("src/main.rs", "fn main() {}");
 
-    assert_that(p.cargo_process("run"), execs().with_status(0));
+    assert_that(p.cargo_process("run").arg("-v"), execs().with_status(0));
     assert_that(&p.bin("foo"), existing_file());
     if cfg!(windows) {
         // On windows unlinking immediately after running often fails, so sleep
         sleep_ms(100);
     }
     fs::remove_file(&p.bin("foo")).unwrap();
-    assert_that(p.cargo("run"),
+    assert_that(p.cargo("run").arg("-v"),
                 execs().with_status(0));
 }
 
@@ -2243,11 +2236,7 @@ fn explicit_color_config_is_propagated_to_rustc() {
     assert_that(p.cargo_process("build").arg("-v").arg("--color").arg("never"),
                 execs().with_status(0).with_stderr("\
 [COMPILING] test v0.0.0 ([..])
-[RUNNING] `rustc src[..]lib.rs --color never --crate-name test --crate-type lib -g \
-        --out-dir [..]target[..]debug \
-        --emit=dep-info,link \
-        -L dependency=[..]target[..]debug \
-        -L dependency=[..]target[..]debug[..]deps`
+[RUNNING] `rustc [..] --color never [..]`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 "));
 }
index 52352bccee3390d290cd475addb5747c3e55a2e8..c026382e4d005c829c6fe1dcfb8393152c4e742c 100644 (file)
@@ -56,8 +56,7 @@ fn alias_config() {
                 execs().with_status(0).
                 with_stderr_contains("[COMPILING] foo v0.5.0 [..]
 [RUNNING] `rustc [..] --crate-name foo --crate-type \
-bin -g --out-dir [..] --emit=dep-info,link -L dependency=[..]\
--L dependency=[..]"));
+bin -g --out-dir [..] --emit=dep-info,link -L dependency=[..]"));
 }
 
 #[test]
index f078bbd94f31d5c4bd0127c6af57ece890748058..55371af3afcc454e66c5cb78bbc7d57173d85143 100644 (file)
@@ -362,7 +362,6 @@ fn linker_and_ar() {
     --emit=dep-info,link \
     --target {target} \
     -C ar=my-ar-tool -C linker=my-linker-tool \
-    -L dependency={dir}[..]target[..]{target}[..]debug \
     -L dependency={dir}[..]target[..]{target}[..]debug[..]deps`
 ",
                             dir = p.root().display(),
index 7adffed9edf7be837f54698801fe384a2f0eb0b4..2da8965da2b95421b77815dafd774d363a5b0a4d 100644 (file)
@@ -147,7 +147,7 @@ fn plugin_with_dynamic_native_dependency() {
 
             fn main() {
                 let src = PathBuf::from(env::var("SRC").unwrap());
-                println!("cargo:rustc-flags=-L {}", src.parent().unwrap()
+                println!("cargo:rustc-flags=-L {}/deps", src.parent().unwrap()
                                                        .display());
             }
         "#)
index 3036d6ca063606a667ef56c26fb759002c27f50e..52fe001972f87b0211fb8274eaf047318f4b8856 100644 (file)
@@ -31,9 +31,8 @@ fn profile_overrides() {
         -C opt-level=1 \
         -C debug-assertions=on \
         -C rpath \
-        --out-dir {dir}{sep}target{sep}debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [optimized] target(s) in [..]
 ", sep = SEP,
@@ -84,23 +83,19 @@ fn top_level_overrides_deps() {
         --crate-type dylib --crate-type rlib -C prefer-dynamic \
         -C opt-level=1 \
         -g \
-        -C metadata=[..] \
-        -C extra-filename=-[..] \
         --out-dir {dir}{sep}target{sep}release{sep}deps \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}release{sep}deps \
         -L dependency={dir}{sep}target{sep}release{sep}deps`
 [COMPILING] test v0.0.0 ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name test --crate-type lib \
         -C opt-level=1 \
         -g \
-        --out-dir {dir}{sep}target{sep}release \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}release \
         -L dependency={dir}{sep}target{sep}release{sep}deps \
         --extern foo={dir}{sep}target{sep}release{sep}deps{sep}\
-                     {prefix}foo-[..]{suffix} \
-        --extern foo={dir}{sep}target{sep}release{sep}deps{sep}libfoo-[..].rlib`
+                     {prefix}foo[..]{suffix} \
+        --extern foo={dir}{sep}target{sep}release{sep}deps{sep}libfoo.rlib`
 [FINISHED] release [optimized + debuginfo] target(s) in [..]
 ",
                     dir = p.root().display(),
index 9723e7d19c08bb88d447a55a6dc7c53532331da7..90e195f6eeae489f53c5234645635fea204200c7 100644 (file)
@@ -411,20 +411,16 @@ fn example_with_release_flag() {
 [COMPILING] bar v0.0.1 ({url}/bar)
 [RUNNING] `rustc bar{sep}src{sep}bar.rs --crate-name bar --crate-type lib \
         -C opt-level=3 \
-        -C metadata=[..] \
-        -C extra-filename=[..] \
         --out-dir {dir}{sep}target{sep}release{sep}deps \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}release{sep}deps \
         -L dependency={dir}{sep}target{sep}release{sep}deps`
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `rustc examples{sep}a.rs --crate-name a --crate-type bin \
         -C opt-level=3 \
         --out-dir {dir}{sep}target{sep}release{sep}examples \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}release \
         -L dependency={dir}{sep}target{sep}release{sep}deps \
-         --extern bar={dir}{sep}target{sep}release{sep}deps{sep}libbar-[..].rlib`
+         --extern bar={dir}{sep}target{sep}release{sep}deps{sep}libbar.rlib`
 [FINISHED] release [optimized] target(s) in [..]
 [RUNNING] `target{sep}release{sep}examples{sep}a[..]`
 ",
@@ -441,20 +437,16 @@ fast2"));
 [COMPILING] bar v0.0.1 ({url}/bar)
 [RUNNING] `rustc bar{sep}src{sep}bar.rs --crate-name bar --crate-type lib \
         -g \
-        -C metadata=[..] \
-        -C extra-filename=[..] \
         --out-dir {dir}{sep}target{sep}debug{sep}deps \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug{sep}deps \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `rustc examples{sep}a.rs --crate-name a --crate-type bin \
         -g \
         --out-dir {dir}{sep}target{sep}debug{sep}examples \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps \
-         --extern bar={dir}{sep}target{sep}debug{sep}deps{sep}libbar-[..].rlib`
+         --extern bar={dir}{sep}target{sep}debug{sep}deps{sep}libbar.rlib`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 [RUNNING] `target{sep}debug{sep}examples{sep}a[..]`
 ",
index 7255c4e00e60c895ef685d39aaf8fc1ad8eb3af0..79e49fdab08617b07ee2cbd6b9681ab1f1775936 100644 (file)
@@ -30,9 +30,8 @@ fn build_lib_for_foo() {
                 .with_stderr(format!("\
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name foo --crate-type lib -g \
-        --out-dir {dir}{sep}target{sep}debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
@@ -61,9 +60,8 @@ fn lib() {
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name foo --crate-type lib -g \
         -C debug-assertions=off \
-        --out-dir {dir}{sep}target{sep}debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
@@ -91,17 +89,15 @@ fn build_main_and_allow_unstable_options() {
                 .with_stderr(&format!("\
 [COMPILING] {name} v{version} ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name {name} --crate-type lib -g \
-        --out-dir {dir}{sep}target{sep}debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [RUNNING] `rustc src{sep}main.rs --crate-name {name} --crate-type bin -g \
         -C debug-assertions \
-        --out-dir {dir}{sep}target{sep}debug \
+        --out-dir [..] \
         --emit=dep-info,link \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps \
-        --extern {name}={dir}{sep}target{sep}debug{sep}lib{name}.rlib`
+        --extern {name}={dir}{sep}target[..]lib{name}.rlib`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
             dir = p.root().display(), url = p.url(),
@@ -156,12 +152,11 @@ fn build_with_args_to_one_of_multiple_binaries() {
                 .with_stderr(format!("\
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name foo --crate-type lib -g \
-        --out-dir {dir}{sep}target{sep}debug [..]`
+        --out-dir [..]`
 [RUNNING] `rustc src{sep}bin{sep}bar.rs --crate-name bar --crate-type bin -g \
         -C debug-assertions [..]`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-", sep = SEP,
-                dir = p.root().display(), url = p.url())));
+", sep = SEP, url = p.url())));
 }
 
 #[test]
@@ -212,12 +207,11 @@ fn build_with_args_to_one_of_multiple_tests() {
                 .with_stderr(format!("\
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `rustc src{sep}lib.rs --crate-name foo --crate-type lib -g \
-        --out-dir {dir}{sep}target{sep}debug [..]`
+        --out-dir [..]`
 [RUNNING] `rustc tests{sep}bar.rs --crate-name bar -g \
         -C debug-assertions [..]--test[..]`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
-", sep = SEP,
-                dir = p.root().display(), url = p.url())));
+", sep = SEP, url = p.url())));
 }
 
 #[test]
@@ -255,7 +249,7 @@ fn build_foo_with_bar_dependency() {
                 .with_status(0)
                 .with_stderr(format!("\
 [COMPILING] bar v0.1.0 ([..])
-[RUNNING] `[..] -g -C [..]`
+[RUNNING] `[..] -g [..]`
 [COMPILING] foo v0.0.1 ({url})
 [RUNNING] `[..] -g -C debug-assertions [..]`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
index de4bd8d57fb62f4395da1a5bde89f0bd3e27e49e..da1336f05bbe983d4589f3c90c3f6f6e01a95ffd 100644 (file)
@@ -24,7 +24,6 @@ fn rustdoc_simple() {
 [DOCUMENTING] foo v0.0.1 ({url})
 [RUNNING] `rustdoc src{sep}lib.rs --crate-name foo \
         -o {dir}{sep}target{sep}doc \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
@@ -50,7 +49,6 @@ fn rustdoc_args() {
 [RUNNING] `rustdoc src{sep}lib.rs --crate-name foo \
         -o {dir}{sep}target{sep}doc \
         --no-defaults \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
@@ -97,7 +95,6 @@ fn rustdoc_foo_with_bar_dependency() {
 [RUNNING] `rustdoc src{sep}lib.rs --crate-name foo \
         -o {dir}{sep}target{sep}doc \
         --no-defaults \
-        -L dependency={dir}{sep}target{sep}debug \
         -L dependency={dir}{sep}target{sep}debug{sep}deps \
         --extern [..]`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
@@ -144,7 +141,6 @@ fn rustdoc_only_bar_dependency() {
 [RUNNING] `rustdoc [..]bar{sep}src{sep}lib.rs --crate-name bar \
         -o {dir}{sep}target{sep}doc \
         --no-defaults \
-        -L dependency={dir}{sep}target{sep}debug{sep}deps \
         -L dependency={dir}{sep}target{sep}debug{sep}deps`
 [FINISHED] debug [unoptimized + debuginfo] target(s) in [..]
 ", sep = SEP,
index c482940c57afaf26c3cf275bcd81f137d6bd78db..b17b56526ad081afcb4ab83374a78bb19701f087 100644 (file)
@@ -2,7 +2,7 @@
 extern crate cargotest;
 extern crate hamcrest;
 
-use std::io::Read;
+use std::io::{Read, Write};
 use std::fs::File;
 
 use cargotest::support::{project, execs};
@@ -827,3 +827,49 @@ fn lock_doesnt_change_depending_on_crate() {
 
     assert_eq!(lockfile, lockfile2);
 }
+
+#[test]
+fn rebuild_please() {
+    let p = project("foo")
+        .file("Cargo.toml", r#"
+            [workspace]
+            members = ['lib', 'bin']
+        "#)
+        .file("lib/Cargo.toml", r#"
+            [package]
+            name = "lib"
+            version = "0.1.0"
+        "#)
+        .file("lib/src/lib.rs", r#"
+            pub fn foo() -> u32 { 0 }
+        "#)
+        .file("bin/Cargo.toml", r#"
+            [package]
+            name = "bin"
+            version = "0.1.0"
+
+            [dependencies]
+            lib = { path = "../lib" }
+        "#)
+        .file("bin/src/main.rs", r#"
+            extern crate lib;
+
+            fn main() {
+                assert_eq!(lib::foo(), 0);
+            }
+        "#);
+    p.build();
+
+    assert_that(p.cargo("run").cwd(p.root().join("bin")),
+                execs().with_status(0));
+
+    t!(t!(File::create(p.root().join("lib/src/lib.rs"))).write_all(br#"
+        pub fn foo() -> u32 { 1 }
+    "#));
+
+    assert_that(p.cargo("build").cwd(p.root().join("lib")),
+                execs().with_status(0));
+
+    assert_that(p.cargo("run").cwd(p.root().join("bin")),
+                execs().with_status(101));
+}